package com.ny.zmb.openapi.demo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.ny.zmb.openapi.util.*;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 资金业务demo
 */
public class FundsDemo {

    private static final String ALLCHAR = "0123456789ABCDEF";

    /**
     * 发起方商户号 服务商在银盛给自己开设的商户号，即可当作发起方商户号
     * 生产环境需要使用自己的发起发商户号，并找相应的对接人员开通所需要的接口权限，并告知是国密还是RSA
     */
    private static final String CERT_ID = "826440345119153";

    /**
     * 银盛端公钥证书
     * 生产环境需要自行去开放平台上下载银盛公钥证书，也可以找对接人提供
     */
    private static final String YS_PUBLIC_CER_PATH = "D:/datas/SHA-test/service.cer";

    /**
     * 商户端的私钥证书
     * 生产环境需要使用自己生产的私钥证书
     */
    private static final String MERC_PRIVATE_FILE = "D:/datas/SHA-test/826440345119153/client.pfx";

    /**
     * 商户端私钥证书密码
     * 生产环境需要使用自己私钥的密码
     */
    private static final String MERC_PRIVATE_FILE_PASSWORD = "123456";

    /**
     * 请求地址域名
     */
    private static final String HTTP_NET = "https://ysgate.ysepay.com";
    //测试 https://appdev.ysepay.com
    //生产 https://ysgate.ysepay.com

    public static void main(String[] args) throws Exception {
        //结算卡绑定
        //settlementAccountDemo();

        //线下汇款充值
        //rechargeDemo();

        //结算进度查询Demo
        //settleProgressDemo();

        //新增定时结算配置demo
        //settleFixedAdd();

        //修改定时结算配置demo
        //settleFixedUpdate();

        //查询定时结算配置demo
        //settleFixedQuery();

        //商户余额查询
        //balanceQueryDemo();

        //商户提现查询
        //withdrawQueryDemo();

        //日对账单下载地址获取
        unionAccDownloadDemo();
    }

    /**
     * 商户提现查询
     * @throws Exception
     */
    private static void unionAccDownloadDemo() throws Exception{
        String httpUrl = HTTP_NET+"/openapi/unify/unionAccDownload";
        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        reqMap.put("method", "openapi.unify.unionAccDownload");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        reqMap.put("certId",CERT_ID);//测试环境可以用这个
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String check = Base64.encodeBase64String(byte1);
        reqMap.put("check",check);//加密后的密钥

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //商户号，此商户号一定要是该发起发下的商户号
        bizContentMap.put("accountDate","20190120");

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizConten = Base64.encodeBase64String(bte);
        reqMap.put("bizContent",msgBizConten);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {
            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/


            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            if(StringUtils.isNotBlank(resMap.get("businessData"))) {
                byte[] data_ = Base64.decodeBase64(resMap.get("businessData"));
                byte[] data = AESUtil.decrypt(data_,ByteUtil.hexStringToBytes(key));
                resMap.put("businessData", new String(data,"UTF-8"));
                System.out.println("解密后的业务参数:"+new String(data,"UTF-8"));
            }
            System.out.println("解密后的完整参数为:"+JSONObject.toJSONString(resMap));
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    /**
     * 商户提现查询
     * @throws Exception
     */
    private static void withdrawQueryDemo() throws Exception{
        String httpUrl = HTTP_NET+"/openapi/unify/merchant/withdraw/quick/query";
        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        reqMap.put("method", "openapi.unify.merchant.withdraw.quick.query");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        reqMap.put("certId",CERT_ID);//测试环境可以用这个
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String check = Base64.encodeBase64String(byte1);
        reqMap.put("check",check);//加密后的密钥

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //商户号，此商户号一定要是该发起发下的商户号
        bizContentMap.put("orderId","20230329054555L7I4");
        bizContentMap.put("shopDate","20230329");

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizConten = Base64.encodeBase64String(bte);
        reqMap.put("bizContent",msgBizConten);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {
            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/


            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            if(StringUtils.isNotBlank(resMap.get("businessData"))) {
                byte[] data_ = Base64.decodeBase64(resMap.get("businessData"));
                byte[] data = AESUtil.decrypt(data_,ByteUtil.hexStringToBytes(key));
                resMap.put("businessData", new String(data,"UTF-8"));
                System.out.println("解密后的业务参数:"+new String(data,"UTF-8"));
            }
            System.out.println("解密后的完整参数为:"+JSONObject.toJSONString(resMap));
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    /**
     * 商户余额查询
     * @throws Exception
     */
    private static void balanceQueryDemo() throws Exception{
        String httpUrl = HTTP_NET+"/openapi/unify/merchant/balance/query";
        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        reqMap.put("method", "openapi.unify.merchant.balance.query");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        reqMap.put("certId",CERT_ID);//测试环境可以用这个
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String check = Base64.encodeBase64String(byte1);
        reqMap.put("check",check);//加密后的密钥

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //商户号，此商户号一定要是该发起发下的商户号
        bizContentMap.put("mercId","dsf2");

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizConten = Base64.encodeBase64String(bte);
        reqMap.put("bizContent",msgBizConten);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {
            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/


            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            if(StringUtils.isNotBlank(resMap.get("businessData"))) {
                byte[] data_ = Base64.decodeBase64(resMap.get("businessData"));
                byte[] data = AESUtil.decrypt(data_,ByteUtil.hexStringToBytes(key));
                resMap.put("businessData", new String(data,"UTF-8"));
                System.out.println("解密后的业务参数:"+new String(data,"UTF-8"));
            }
            System.out.println("解密后的完整参数为:"+JSONObject.toJSONString(resMap));
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    /**
     * 定时结算查询
     * @throws Exception
     */
    private static void settleFixedQuery() throws Exception{
        String httpUrl = HTTP_NET+"/openapi/pregate/settle/fixed/config/query";
        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        reqMap.put("method", "openapi.pregate.settle.fixed.config.query");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        reqMap.put("certId",CERT_ID);//测试环境可以用这个
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String check = Base64.encodeBase64String(byte1);
        //加密后的密钥
        reqMap.put("check", check);

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //商户号，此商户号一定要是该发起发下的商户号
        bizContentMap.put("mercId","826584859770003");

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizConten = Base64.encodeBase64String(bte);
        reqMap.put("bizContent",msgBizConten);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {
            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/


            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            if(StringUtils.isNotBlank(resMap.get("businessData"))) {
                byte[] data_ = Base64.decodeBase64(resMap.get("businessData"));
                byte[] data = AESUtil.decrypt(data_,ByteUtil.hexStringToBytes(key));
                resMap.put("businessData", new String(data,"UTF-8"));
                System.out.println("解密后的业务参数:"+new String(data,"UTF-8"));
            }
            System.out.println("解密后的完整参数为:"+JSONObject.toJSONString(resMap));
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    /**
     * 定时结算修改
     * @throws Exception
     */
    private static void settleFixedUpdate() throws Exception{
        String httpUrl = HTTP_NET+"/openapi/pregate/settle/fixed/config/update";
        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        reqMap.put("method", "openapi.pregate.settle.fixed.config.update");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        reqMap.put("certId",CERT_ID);//测试环境可以用这个
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String check = Base64.encodeBase64String(byte1);
        //加密后的密钥
        reqMap.put("check", check);

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //商户号，此商户号一定要是该发起发下的商户号
        bizContentMap.put("mercId","826584859770003");
        //结算时间段,0-23,多个结算时间用英文逗号拼接,格式如：1,2,3
        bizContentMap.put("stlTime","0,2");
        bizContentMap.put("state","00");

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizConten = Base64.encodeBase64String(bte);
        reqMap.put("bizContent",msgBizConten);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {
            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/


            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            if(StringUtils.isNotBlank(resMap.get("businessData"))) {
                byte[] data_ = Base64.decodeBase64(resMap.get("businessData"));
                byte[] data = AESUtil.decrypt(data_,ByteUtil.hexStringToBytes(key));
                resMap.put("businessData", new String(data,"UTF-8"));
                System.out.println("解密后的业务参数:"+new String(data,"UTF-8"));
            }
            System.out.println("解密后的完整参数为:"+JSONObject.toJSONString(resMap));
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    /**
     * 新增定时结算配置
     * @throws Exception
     */
    private static void settleFixedAdd() throws Exception{
        String httpUrl = HTTP_NET+"/openapi/pregate/settle/fixed/config/add";
        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        reqMap.put("method", "openapi.pregate.settle.fixed.config.add");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        reqMap.put("certId",CERT_ID);//测试环境可以用这个
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String check = Base64.encodeBase64String(byte1);
        //加密后的密钥
        reqMap.put("check", check);

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //商户号，此商户号一定要是该发起发下的商户号
        bizContentMap.put("mercId","826584859770003");
        //结算时间段,0-23,多个结算时间用英文逗号拼接,格式如：1,2,3
        bizContentMap.put("stlTime","0,2");

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizConten = Base64.encodeBase64String(bte);
        reqMap.put("bizContent",msgBizConten);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {
            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/


            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            if(StringUtils.isNotBlank(resMap.get("businessData"))) {
                byte[] data_ = Base64.decodeBase64(resMap.get("businessData"));
                byte[] data = AESUtil.decrypt(data_,ByteUtil.hexStringToBytes(key));
                resMap.put("businessData", new String(data,"UTF-8"));
                System.out.println("解密后的业务参数:"+new String(data,"UTF-8"));
            }
            System.out.println("解密后的完整参数为:"+JSONObject.toJSONString(resMap));
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    private static void settleProgressDemo() throws Exception{
        String httpUrl = HTTP_NET+"/openapi/pregate/settle/progressNotOrg";

        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        reqMap.put("method", "openapi.pregate.settle.progressNotOrg");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        reqMap.put("certId",CERT_ID);//测试环境可以用这个
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。YS_PUBLIC_CER_PATH为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String encryptKey = Base64.encodeBase64String(byte1);
        reqMap.put("check",encryptKey);//加密后的密钥

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //请求流水
        bizContentMap.put("reqMsgId",String.valueOf(System.currentTimeMillis()));
        //商户号集合
        List<String> mercIds = new ArrayList<>();
        mercIds.add("auto_order017");
        bizContentMap.put("mercIds", mercIds);
        //结算开始日期
        bizContentMap.put("stlStartDate","20211001");
        //结算结束日期
        bizContentMap.put("stlEndDate","20211018");
        //结算状态
        bizContentMap.put("payState","00");
        //分页参数
        bizContentMap.put("pageNum",1);
        bizContentMap.put("pageSize",10);

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizConten = Base64.encodeBase64String(bte);
        reqMap.put("bizContent",msgBizConten);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {

            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/


            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            byte[] dataEncode=Base64.decodeBase64(resMap.get("businessData"));
            byte[] data= AESUtil.decrypt(dataEncode, ByteUtil.hexStringToBytes(key));
            String businessData=new String(data,"UTF-8");
            System.out.println("返回的业务参数为:"+businessData);
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    private static void rechargeDemo() throws Exception {
        String httpUrl = HTTP_NET+"/openapi/prepose/portalRecharge";

        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        //接口方法名，根据接口文档取值
        reqMap.put("method", "manager.portal.recharge.rechargeOffline.1.0.0");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        //固定utf-8
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        //银盛商户号
//       reqMap.put("certId","826440345119153");//826440345119153测试环境可用商户号
        reqMap.put("certId", CERT_ID);
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String encryptKey = Base64.encodeBase64String(byte1);
        reqMap.put("check",encryptKey);//加密后的密钥

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //请求流水
        bizContentMap.put("reqMsgId",String.valueOf(System.currentTimeMillis()));
        //商户号
        bizContentMap.put("mercId", "826440345119153");
        //手机号
        bizContentMap.put("mobile","13677377165");
        //结算结束日期
        bizContentMap.put("rechargeAmount",100.1);
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizContent = Base64.encodeBase64String(bte);
        reqMap.put("bizContent", msgBizContent);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {
            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/

            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            byte[] dataEncode=Base64.decodeBase64(resMap.get("businessData"));
            byte[] data= AESUtil.decrypt(dataEncode, ByteUtil.hexStringToBytes(key));
            String businessData=new String(data,"UTF-8");
            System.out.println("返回的业务参数为:"+businessData);
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    private static void settlementAccountDemo() throws Exception {
        String httpUrl = HTTP_NET+"/openapi/prepose/settlementAccount/bind";

        /** 1、封装请求参数，bizContent（业务参数，需要加密）和chec（需要生成密钥并加密）后面设置值*/
        Map<String,String> reqMap = new HashMap<String,String>();
        //接口方法名，根据接口文档取值
        reqMap.put("method", "prepose.settlementAccount.bind");
        reqMap.put("timeStamp",getCurrentDateTime("yyyy-MM-dd HH:mm:dd"));
        //固定utf-8
        reqMap.put("charset","utf-8");
        reqMap.put("reqId",String.valueOf(System.currentTimeMillis()));
        //银盛商户号 826440345119153测试环境可用商户号
        reqMap.put("certId",CERT_ID);
        reqMap.put("version","1.0");

        /** 2、生成对业务参数加密的密钥*/
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(ALLCHAR.charAt(random.nextInt(ALLCHAR.length())));
        }
        String key = ByteUtil.toHexString(sb.toString());

        /** 3、使用银盛公钥对密钥key进行加密，得到加密的key并设置到请求参数check中。publicFilePath为存放银盛公钥的地址*/
        byte[] byte1= RSA256Util.encrypt(YS_PUBLIC_CER_PATH, ByteUtil.hexStringToBytes(key));
        String encryptKey = Base64.encodeBase64String(byte1);
        reqMap.put("check",encryptKey);//加密后的密钥

        /** 4、封装业务参数,具体参数见文档，这里只是举例子*/
        Map<String,Object> bizContentMap = new HashMap<>();
        //请求流水
        bizContentMap.put("reqMsgId", String.valueOf(System.currentTimeMillis()));
        bizContentMap.put("userCode", "826440345119153");
        bizContentMap.put("bankaccountNo", "6217007200027711100");
        bizContentMap.put("banktype", "1051000");
        bizContentMap.put("bankaddrNo", "5840");
        bizContentMap.put("bankaccountType", "11");
        bizContentMap.put("openBankname", "中国建设银行股份有限公司深圳南新支行");
        JSONObject bizJSONObj = JSONObject.parseObject(JSON.toJSONString(bizContentMap));

        /** 5、使用生成的密钥key对业务参数进行加密，并将加密后的业务参数放入请求参数bizContent中*/
        byte[] bte= AESUtil.encrypt(JSONObject.toJSONBytes(bizJSONObj,SerializerFeature.WriteNullStringAsEmpty), ByteUtil.hexStringToBytes(key));
        String msgBizContent = Base64.encodeBase64String(bte);
        reqMap.put("bizContent", msgBizContent);

        /** 6、将请求参数进行sort排序，生成拼接的字符床，并使用接入方私钥对请求参数进行加签，并将加签的值存入请求参数sign中*/
        //6.1 排序生成拼接字符串
        List<String> keys = new ArrayList<String>(reqMap.keySet());
        Collections.sort(keys);
        StringBuilder sb1 = new StringBuilder();
        for(String k : keys){
            if("sign".equals(k)) {
                continue;
            }
            sb1.append(k).append("=");
            sb1.append(reqMap.get(k));
            sb1.append("&");
        }
        if(sb1.length() > 0) {
            sb1.setLength(sb1.length() - 1);
        }
        //6.2使用接入方私钥对排序的请求参数加签，并存放到请求参数里面.privateFilePath:私钥地址，prvatePassword:私钥密钥
        String sign= RSA256Util.sign(sb1.toString(),MERC_PRIVATE_FILE,MERC_PRIVATE_FILE_PASSWORD);
        reqMap.put("sign",sign );

        /** 7、发送http请求获取返回结果，请求地址以文档为准*/
        try {

            String result = HttpRequestUtil.getDoPostResponse(httpUrl, reqMap, "UTF-8", null, 20*1000);
            byte[] res = Base64.decodeBase64(result);
            Map<String, String> resMap = (Map<String, String>) JSONObject.parse(new String(res,"UTF-8"));
            System.out.println("http请求返回的结果为:"+JSONObject.toJSONString(resMap));

            /** 8、对结果进行解密，并使用银盛公钥验签*/
            if(StringUtils.isNotBlank(resMap.get("sign"))) {
                byte[] srcData = SignUtil.getSignDataStr1(resMap).getBytes("UTF-8");
                boolean validateSignResult= RSA256Util.validateSign(YS_PUBLIC_CER_PATH,Base64.decodeBase64(resMap.get("sign")),srcData);
                if(!validateSignResult){
                    System.out.println("验签失败");
                    throw new Exception("验签失败");
                }
            }else{
                throw new Exception("验签失败,未返回加签信息,可能是银盛未配置发起方或者发起方证书类型配置有误,返回结果提示为:{}"+resMap.get("msg"));
            }

            /** 9、针对自己的业务，根据返回的结果的code 和 subCode 做接入方的业务处理*/

            /** 10、使用上面生成的加密密钥key，解密返回的业务参数*/
            byte[] dataEncode=Base64.decodeBase64(resMap.get("businessData"));
            byte[] data= AESUtil.decrypt(dataEncode, ByteUtil.hexStringToBytes(key));
            String businessData=new String(data,"UTF-8");
            System.out.println("返回的业务参数为:"+businessData);
        } catch (Exception e) {
            e.printStackTrace();
            throw  e;
        }
    }

    /**
     * 格式化当前日期时间字符串
     * @return
     */
    private static  String getCurrentDateTime(String pattern){
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(new Date());
    }
}
